/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2005
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
* 
* Author's email :    insane@dees.ufmg.br
* Author's website :  http://www.dees.ufmg.br/insane
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package br.ufmg.dees.insane.assembler;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Set;

import br.ufmg.dees.insane.model.femModel.Model;
import br.ufmg.dees.insane.model.femModel.element.Element;
import br.ufmg.dees.insane.model.femModel.node.Node;
import br.ufmg.dees.insane.util.IMatrix;
import br.ufmg.dees.insane.util.IVector;
import br.ufmg.dees.insane.util.LoadCase;
import br.ufmg.dees.insane.util.LoadCombination;
import br.ufmg.dees.insane.util.pointValues.DoublePointValues;
import br.ufmg.dees.insane.util.pointValues.IntPointValues;


/**
*A class representing an assembler FemModel equation Ax" + Bx' + Cx = R - F 
*partitioned in the form<br>
*|	Cuu  |	Cup	 ||Xu| |Rp| |Fp|<br>
*|-------|-------||--|=|--|-|--|<br>
*|	Cpu	 |	Cpp	 ||Xp| |Ru| |Fu|<br>	
*
*@author Roque, Marcos, Samir, Flavio, Jamile
*@version 1.0
*@since 24/07/2005
*/

/**
 * Class representing FemAssembler
 * @author roque
 * @since Jul 27, 2005
 */
public class FemAssembler implements Assembler, Serializable {
    
	private static final long serialVersionUID = 1L;

	/**The FemModel of this Assembler.*/
	private Model femModel;
	
	/** The size of the vector Xu 
	*It is the same of the number of degrees of freedom of the FemModel.
	*/
	protected int sizeOfXu;
	
	/** The size of the vector Xp.*/
	protected int sizeOfXp;
	
	/** Indicates if the equation system is singular or not.*/
	protected boolean isSingular = false;
		
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#getModel()
	 */
	public Model getModel() {
		return this.femModel;
	};	
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#setModel(br.ufmg.dees.insane.model.femModel.Model)
	 */
	public void setModel(Model a){
		this.femModel = a;
	}
	
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#getSizeOfXu()
	 */
	public int getSizeOfXu(){
		return this.sizeOfXu;
	}

	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#setSizeOfXu(int)
	 */
	public void setSizeOfXu(int a){
		this.sizeOfXu = a;
	};
	
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#getSizeOfXp()
	 */
	public int getSizeOfXp(){
		return this.sizeOfXp;
	}
	
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#setSizeOfXp(int)
	 */
	public void setSizeOfXp(int a){
		this.sizeOfXp = a;
	};
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#setSingular(boolean)
	 */
	public void setSingular(boolean a) {
	    isSingular = a;
	}

	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#isSingular()
	 */
	public boolean isSingular() {
	    return isSingular;
	}
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#getCpu()
	 */
	public IMatrix getCpu()
	{
		IMatrix k = new IMatrix(this.getSizeOfXp(), this.getSizeOfXu());
		k.setZero();
		ListIterator elements = femModel.getElementsList().listIterator();
		while (elements.hasNext())
		{
			Element element = (Element) elements.next();
			int[] redEquations = this.getElementEquations(element);
            IMatrix c = element.getC();
			//Adding elements' stiffness matrix to model's stiffness matrix
			for (int i=0; i<element.getNumberOfDegreesOfFreedom(); i++)
			{
				for (int j=0; j<element.getNumberOfDegreesOfFreedom(); j++)
				{
					int a = redEquations[i];
					int b = redEquations[j];
					if (a<0 && b>0)
					{
						k.setElement((-a)-1, b-1, k.getElement((-a)-1, b-1) + c.getElement(i, j));
					};
				};
			};
		};
		
		return(k);
	};
	
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#getCup()
	 */
	public IMatrix getCup()
	{
		IMatrix k = new IMatrix(this.getSizeOfXu(),this.getSizeOfXp());
		k.setZero();
		ListIterator elements = femModel.getElementsList().listIterator();
		while (elements.hasNext())
		{
			Element element = (Element) elements.next();
			int[] redEquations = this.getElementEquations(element);
            IMatrix c = element.getC();
			//Adding elements' stiffness matrix to model's stiffness matrix
			for (int i=0; i<element.getNumberOfDegreesOfFreedom(); i++)
			{
				for (int j=0; j<element.getNumberOfDegreesOfFreedom(); j++)
				{
					int a = redEquations[i];
					int b = redEquations[j];
					if (a>0 && b<0)
					{
						k.setElement(a-1, (-b)-1, k.getElement(a-1, (-b)-1) + c.getElement(i, j));
					};
				};
			};
		};
		return(k);
	};
	
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#getCpp()
	 */
	public IMatrix getCpp(){
		IMatrix k = new IMatrix(this.getSizeOfXp(), this.getSizeOfXp());
		k.setZero();
		ListIterator elements = femModel.getElementsList().listIterator();
		while (elements.hasNext()) {
			Element element = (Element) elements.next();
			int[] redEquations = this.getElementEquations(element);
            IMatrix c = element.getC();
			//Adding elements' stiffness matrix to model's stiffness matrix
			for (int i=0; i<element.getC().getNumRow(); i++){
				for (int j=0; j<element.getC().getNumCol(); j++){
					int a = redEquations[i];
					int b = redEquations[j];
					if (a<0 && b<0){
						k.setElement((-a)-1, (-b)-1, k.getElement((-a)-1, (-b)-1) + c.getElement(i, j));
					};
				};
			};
		};
		
		return(k);
	};
	
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#getCuu()
	 */
	public IMatrix getCuu(){
		IMatrix kr = new IMatrix(this.getSizeOfXu(), this.getSizeOfXu());
		kr.setZero();
		ListIterator elements = femModel.getElementsList().listIterator();
		while (elements.hasNext()) {
			Element element = (Element) elements.next();
			int[] redEquations = this.getElementEquations(element);
            IMatrix c = element.getC();
			//Adding elements' stiffness matrix to model's stiffness matrix
			for (int i=0; i<element.getNumberOfDegreesOfFreedom(); i++){
				for (int j=0; j<element.getNumberOfDegreesOfFreedom(); j++){
					int a = redEquations[i];
					int b = redEquations[j];
					if (a>0 && b>0){
						kr.setElement(a-1, b-1, kr.getElement(a-1, b-1) + c.getElement(i, j));
					}
				}
			}
		}
		
		//Adding nodal stiffness to model's stiffness matrix
		ListIterator nodes = femModel.getNodesList().listIterator();
		while (nodes.hasNext()) {
			Node node = (Node) nodes.next();
			if (node.nodeValuesContainsKey("COEFICIENTS_C")) {
				for (int i=0; i<node.getNumberOfDegreesOfFreedom(); i++) {
					int pos = node.getNodeValues(node.EQUATIONS).getIntPointValue(i);
					if (pos > 0) {
						kr.setElement(pos-1, pos-1, kr.getElement(pos-1, pos-1) + node.getNodeValues(node.COEFICIENTS_C).getDoublePointValue(i));
					}
				}
			}
		}
		return(kr);
	}
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#setXu(br.ufmg.dees.insane.util.IVector)
	 */
	public void setXu(IVector Xu){
	    Node node;
		ListIterator nodes = femModel.getNodesList().listIterator();
		while (nodes.hasNext()){
			node = (Node) nodes.next();
			for (int i=0; i<node.getNumberOfDegreesOfFreedom(); i++){
				if (node.getNodeValues(node.EQUATIONS).getIntPointValue(i) > 0)
					node.getNodeValues(Node.STATE_VARIABLE).setPointValueAsDouble(i,Xu.getElement(node.getNodeValues(node.EQUATIONS).getIntPointValue(i)-1));
			};
		};
	};
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#getXu()
	 */
	public IVector getXu(){
		IVector aux = new IVector (this.getSizeOfXu());
        aux.zero();
		ListIterator nodes = femModel.getNodesList().listIterator();
		int j = 0;
		while (nodes.hasNext()) {
			Node node = (Node)nodes.next();
            if(node.nodeValuesContainsKey(Node.STATE_VARIABLE)){
                for (int i=0; i<node.getNumberOfDegreesOfFreedom(); i++) {
                    if (node.getNodeValues(node.EQUATIONS).getIntPointValue(i)>0) {
                        aux.setElement(j, node.getNodeValues(Node.STATE_VARIABLE).getDoublePointValue(i));
                        j++;
                    };
                };
            }
		};
		return (aux);
	};
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#setXp()
	 */
	public void setXp()
	{
		ListIterator nodes = femModel.getNodesList().listIterator();
		while (nodes.hasNext())
		{
			Node node = (Node) nodes.next();
			if (node.nodeValuesContainsKey(Node.PRE_STATE_VARIABLE)&& node.nodeValuesContainsKey(Node.STATE_VARIABLE)) {
			    for (int i=0; i<node.getNumberOfDegreesOfFreedom(); i++)
				{
						((DoublePointValues)node.getNodeValues(Node.STATE_VARIABLE)).addDoublePointValue(i,node.getNodeValues(Node.PRE_STATE_VARIABLE).getDoublePointValue(i));
				}
            }
		}
	}
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#getXp()
	 */
	public IVector getXp()
	{
		IVector pdv = new IVector(this.getSizeOfXp());
		ListIterator nodes = femModel.getNodesList().listIterator();
		while (nodes.hasNext())
		{
			Node node = (Node) nodes.next();
//			  Storing nodes' equivalent DualVariable vector to model's prescribed X vector
				for (int i=0; i<node.getNumberOfDegreesOfFreedom(); i++)
				{
					int a = node.getNodeValues(node.EQUATIONS).getIntPointValue(i);
					if (a<0)
					{
					    if (node.nodeValuesContainsKey(Node.PRE_STATE_VARIABLE)) {
					        pdv.setElement(-a-1, node.getNodeValues(Node.PRE_STATE_VARIABLE).getDoublePointValue(i));
					    }
					    else {
					        pdv.setElement(-a-1, 0.0);
					    }
					};
				};
			}
		return(pdv);
	};
    
    /* (non-Javadoc)
     * @see br.ufmg.dees.insane.assembler.Assembler#getNp()
     */
    public IVector getNp(){
        IVector pr = new IVector(this.getSizeOfXu());
        ListIterator nodes = femModel.getNodesList().listIterator();
        while (nodes.hasNext()) {
            Node node = (Node) nodes.next();
            if (node.nodeValuesContainsKey(Node.DUAL_VARIABLE)){
            for (int i=0; i<node.getNumberOfDegreesOfFreedom(); i++){
                if (node.getNodeValues(node.EQUATIONS).getIntPointValue(i) > 0) {
                        pr.setElement(node.getNodeValues(node.EQUATIONS).getIntPointValue(i)-1, pr.getElement(node.getNodeValues(node.EQUATIONS).getIntPointValue(i)-1) + node.getNodeValues(Node.DUAL_VARIABLE).getDoublePointValue(i));
                        }
                    }
            };
        };
        return (pr);
    };
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#setNu(br.ufmg.dees.insane.util.IVector)
	 */
	public void setNu(IVector Ru)
	{
		Node node;
		ListIterator nodes = femModel.getNodesList().listIterator();
		while (nodes.hasNext())
		{
			node = (Node) nodes.next();
			for (int i=0; i<node.getNumberOfDegreesOfFreedom(); i++)
			{
				if (node.getNodeValues(node.EQUATIONS).getIntPointValue(i) < 0){
				    node.getNodeValues(Node.UNKNOWN_DUAL_VARIABLE).setPointValueAsDouble(i,Ru.getElement((-node.getNodeValues(node.EQUATIONS).getIntPointValue(i))-1));
				}else{
				    node.getNodeValues(Node.UNKNOWN_DUAL_VARIABLE).setPointValueAsDouble(i,0.0);			
				}
			};
		};
	};
    
    /* (non-Javadoc)
     * @see br.ufmg.dees.insane.assembler.Assembler#getNu()
     */
    public IVector getNu(){
        IVector pr = new IVector(this.getSizeOfXp());
        ListIterator nodes = femModel.getNodesList().listIterator();
        while (nodes.hasNext()) {
            Node node = (Node) nodes.next();
            if (node.nodeValuesContainsKey(Node.DUAL_VARIABLE)){
            for (int i=0; i<node.getNumberOfDegreesOfFreedom(); i++){
                if (node.getNodeValues(node.EQUATIONS).getIntPointValue(i) < 0) {
                        pr.setElement((-node.getNodeValues(node.EQUATIONS).getIntPointValue(i))-1, pr.getElement((-node.getNodeValues(node.EQUATIONS).getIntPointValue(i))-1) + node.getNodeValues(Node.DUAL_VARIABLE).getDoublePointValue(i));
                        }
                    }
            };
        };
        return (pr);
    };

   
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#getEp()
	 */
	public IVector getEp(){
		IVector efv = new IVector(this.getSizeOfXu());
		efv.zero();
		ListIterator elements = femModel.getElementsList().listIterator();
		while (elements.hasNext()) {
			Element element = (Element) elements.next();
			int[] redEquations = this.getElementEquations(element);
            IVector e = element.getE();
			//Adding elements' equivalent DualVariable vector to model's equivalent DualVariable vector
			for (int i=0; i<element.getNumberOfDegreesOfFreedom(); i++){
					int a = redEquations[i];
					if (a>0){
						efv.setElement(a-1, efv.getElement(a-1) + e.getElement(i));
					};
			};
		};
		return(efv);
	};
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#getEu()
	 */
	public IVector getEu()
	{
		IVector refv = new IVector(this.getSizeOfXp());
		refv.zero();
		ListIterator elements = femModel.getElementsList().listIterator();
		while (elements.hasNext())
		{
			Element element = (Element) elements.next();
			int[] redEquations = this.getElementEquations(element);
            IVector e = element.getE();
			//Adding elements' stiffness matrix to model's stiffness matrix
			for (int i=0; i<element.getE().getSize(); i++)
			{
				int a = redEquations[i];
				if (a<0)
				{
					refv.setElement((-a)-1, refv.getElement((-a)-1) + e.getElement(i));
				};
			};
		};
		return(refv);
	};
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#getFp()
	 */
	public IVector getFp(){
	    IVector efv = new IVector(this.getSizeOfXu());
	    efv.zero();
	    ListIterator elements = femModel.getElementsList().listIterator();
	    while (elements.hasNext()) {
	        Element element = (Element) elements.next();
	        int[] redEquations = this.getElementEquations(element);
	        //Adding elements' equivalent DualVariable vector to model's equivalent DualVariable vector
	        IVector efvLocal = element.getF();
	        for (int i=0; i<element.getNumberOfDegreesOfFreedom(); i++){
	            	int a = redEquations[i];
	            	if (a>0){
					efv.setElement(a-1, efv.getElement(a-1) + efvLocal.getElement(i));
				};
	        };
	    };
	return(efv);
	};
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#getIncrementalCpu()
	 */
	public IMatrix getIncrementalCpu()
	{
		IMatrix k = new IMatrix(this.getSizeOfXp(), this.getSizeOfXu());
		k.setZero();
		ListIterator elements = femModel.getElementsList().listIterator();
		while (elements.hasNext())
		{
			Element element = (Element) elements.next();
			int[] redEquations = this.getElementEquations(element);
            IMatrix c = element.getIncrementalC();
			//Adding elements' stiffness matrix to model's stiffness matrix
			for (int i=0; i<element.getNumberOfDegreesOfFreedom(); i++)
			{
				for (int j=0; j<element.getNumberOfDegreesOfFreedom(); j++)
				{
					int a = redEquations[i];
					int b = redEquations[j];
					if (a<0 && b>0)
					{
						k.setElement(-a-1, b-1, k.getElement(-a-1, b-1) + c.getElement(i, j));
					};
				};
			};
		};
		
		return(k);
	};
	
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#getIncrementalCup()
	 */
	public IMatrix getIncrementalCup()
	{
		IMatrix k = new IMatrix(this.getSizeOfXp(), this.getSizeOfXu());
		k.setZero();
		ListIterator elements = femModel.getElementsList().listIterator();
		while (elements.hasNext())
		{
			Element element = (Element) elements.next();
			int[] redEquations = this.getElementEquations(element);
            IMatrix c = element.getIncrementalC();
			//Adding elements' stiffness matrix to model's stiffness matrix
			for (int i=0; i<element.getNumberOfDegreesOfFreedom(); i++)
			{
				for (int j=0; j<element.getNumberOfDegreesOfFreedom(); j++)
				{
					int a = redEquations[i];
					int b = redEquations[j];
					if (a>0 && b<0)
					{
						k.setElement(a-1, -b-1, k.getElement(a-1, -b-1) + c.getElement(i, j));
					};
				};
			};
		};
		
		return(k);
	};
	
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#getIncrementalCpp()
	 */
	public IMatrix getIncrementalCpp(){
		IMatrix k = new IMatrix(this.getSizeOfXp(), this.getSizeOfXp());
		k.setZero();
		ListIterator elements = femModel.getElementsList().listIterator();
		while (elements.hasNext()) {
			Element element = (Element) elements.next();
			int[] redEquations = this.getElementEquations(element);
            IMatrix c = element.getIncrementalC();
			//Adding elements' stiffness matrix to model's stiffness matrix
			for (int i=0; i<element.getC().getNumRow(); i++){
				for (int j=0; j<element.getC().getNumCol(); j++){
					int a = redEquations[i];
					int b = redEquations[j];
					if (a<0 && b<0){
						k.setElement(-a-1, -b-1, k.getElement(-a-1, -b-1) + c.getElement(i, j));
					};
				};
			};
		};
		
		return(k);
	};
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#getIncrementalCuu()
	 */
	public IMatrix getIncrementalCuu(){
		IMatrix kr = new IMatrix(this.getSizeOfXu(), this.getSizeOfXu());
		kr.setZero();
		ListIterator elements = femModel.getElementsList().listIterator();
		while (elements.hasNext()) {
			Element element = (Element) elements.next();
			int[] redEquations = this.getElementEquations(element);
            IMatrix c = element.getIncrementalC();
			//Adding elements' stiffness matrix to model's stiffness matrix
			for (int i=0; i<element.getNumberOfDegreesOfFreedom(); i++){
				for (int j=0; j<element.getNumberOfDegreesOfFreedom(); j++){
					int a = redEquations[i];
					int b = redEquations[j];
					if (a>0 && b>0){
						kr.setElement(a-1, b-1, kr.getElement(a-1, b-1) + c.getElement(i, j));
					};
				};
			};
		};
		
		//Adding nodal stiffness to model's stiffness matrix
		ListIterator nodes = femModel.getNodesList().listIterator();
		while (nodes.hasNext()) {
			Node node = (Node) nodes.next();
			if (node.nodeValuesContainsKey("COEFICIENTS_C")) {
			    for (int i=0; i<node.getNumberOfDegreesOfFreedom(); i++) {
					int pos = node.getNodeValues(node.EQUATIONS).getIntPointValue(i);
					if (pos > 0) {
						kr.setElement(pos-1, pos-1, kr.getElement(pos-1, pos-1) + node.getNodeValues(node.COEFICIENTS_C).getDoublePointValue(i));
					};
				};
			}
			}
		return(kr);
	};
	
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#getTotalCpu()
	 */
	public IMatrix getTotalCpu()
	{
		IMatrix k = new IMatrix(this.getSizeOfXp(), this.getSizeOfXu());
		k.setZero();
		ListIterator elements = femModel.getElementsList().listIterator();
		while (elements.hasNext())
		{
			Element element = (Element) elements.next();
			int[] redEquations = this.getElementEquations(element);
            IMatrix c = element.getTotalC();
			//Adding elements' stiffness matrix to model's stiffness matrix
			for (int i=0; i<element.getNumberOfDegreesOfFreedom(); i++)
			{
				for (int j=0; j<element.getNumberOfDegreesOfFreedom(); j++)
				{
					int a = redEquations[i];
					int b = redEquations[j];
					if (a<0 && b>0)
					{
						k.setElement(-a-1, b-1, k.getElement(-a-1, b-1) + c.getElement(i, j));
					};
				};
			};
		};
		
		return(k);
	};
	
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#getTotalCup()
	 */
	public IMatrix getTotalCup()
	{
		IMatrix k = new IMatrix(this.getSizeOfXp(), this.getSizeOfXu());
		k.setZero();
		ListIterator elements = femModel.getElementsList().listIterator();
		while (elements.hasNext())
		{
			Element element = (Element) elements.next();
			int[] redEquations = this.getElementEquations(element);
            IMatrix c = element.getTotalC();
			//Adding elements' stiffness matrix to model's stiffness matrix
			for (int i=0; i<element.getNumberOfDegreesOfFreedom(); i++)
			{
				for (int j=0; j<element.getNumberOfDegreesOfFreedom(); j++)
				{
					int a = redEquations[i];
					int b = redEquations[j];
					if (a>0 && b<0)
					{
						k.setElement(a-1, -b-1, k.getElement(a-1, -b-1) + c.getElement(i, j));
					};
				};
			};
		};
		
		return(k);
	};
	
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#getTotalCpp()
	 */
	public IMatrix getTotalCpp(){
		IMatrix k = new IMatrix(this.getSizeOfXp(), this.getSizeOfXp());
		k.setZero();
		ListIterator elements = femModel.getElementsList().listIterator();
		while (elements.hasNext()) {
			Element element = (Element) elements.next();
			int[] redEquations = this.getElementEquations(element);
            IMatrix c = element.getTotalC();
			//Adding elements' stiffness matrix to model's stiffness matrix
			for (int i=0; i<element.getC().getNumRow(); i++){
				for (int j=0; j<element.getC().getNumCol(); j++){
					int a = redEquations[i];
					int b = redEquations[j];
					if (a<0 && b<0){
						k.setElement(-a-1, -b-1, k.getElement(-a-1, -b-1) + c.getElement(i, j));
					};
				};
			};
		};
		
		return(k);
	};
	
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#getTotalCuu()
	 */
	public IMatrix getTotalCuu(){
		IMatrix kr = new IMatrix(this.getSizeOfXu(), this.getSizeOfXu());
		kr.setZero();
		ListIterator elements = femModel.getElementsList().listIterator();
		while (elements.hasNext()) {
			Element element = (Element) elements.next();
			int[] redEquations = this.getElementEquations(element);
            IMatrix c = element.getTotalC();
			//Adding elements' stiffness matrix to model's stiffness matrix
			for (int i=0; i<element.getNumberOfDegreesOfFreedom(); i++){
				for (int j=0; j<element.getNumberOfDegreesOfFreedom(); j++){
					int a = redEquations[i];
					int b = redEquations[j];
					if (a>0 && b>0){
						kr.setElement(a-1, b-1, kr.getElement(a-1, b-1) + c.getElement(i, j));
					};
				};
			};
		};
		
		//Adding nodal stiffness to model's stiffness matrix
		ListIterator nodes = femModel.getNodesList().listIterator();
		while (nodes.hasNext()) {
			Node node = (Node) nodes.next();
			if (node.nodeValuesContainsKey("COEFICIENTS_C")) {
			    for (int i=0; i<node.getNumberOfDegreesOfFreedom(); i++) {
					int pos = node.getNodeValues(node.EQUATIONS).getIntPointValue(i);
					if (pos > 0) {
						kr.setElement(pos-1, pos-1, kr.getElement(pos-1, pos-1) + node.getNodeValues(node.COEFICIENTS_C).getDoublePointValue(i));
					};
				};
			};
			}
		return(kr);
	}
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#numberEquations()
	 */
	public void numberEquations(){
	    this.setSizeOfXu(0);
		Node node;
		ListIterator nodes = femModel.getNodesList().listIterator();
		while (nodes.hasNext()) {
			node = (Node)nodes.next();
			for (int i=0; i<node.getNumberOfDegreesOfFreedom(); i++){
				if (!node.nodeValuesContainsKey(node.RESTRAINTS) || !node.getNodeValues(node.RESTRAINTS).getBooleanPointValue(i)){
					this.setSizeOfXu(this.getSizeOfXu()+1);
					node.getNodeValues(node.EQUATIONS).setPointValueAsInt(i,this.getSizeOfXu());
				}
				else {
					this.setSizeOfXp(this.getSizeOfXp()+1);
					node.getNodeValues(node.EQUATIONS).setPointValueAsInt(i,-this.getSizeOfXp());
				};
			};
		};
	};
	
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#initEquations()
	 */
	public void initEquations(){
		this.setSizeOfXu(0);
		Node node;
		ListIterator nodes = femModel.getNodesList().listIterator();
		while (nodes.hasNext()) {
		    IntPointValues ipv = new IntPointValues();
			node = (Node)nodes.next();
			for (int i=0; i<node.getNumberOfDegreesOfFreedom(); i++){
			    ipv.setPointValueAsInt(i, 0);
			}
			node.setNodeValues(node.EQUATIONS, ipv);
		};
	};
	
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#init()
	 */
	public void init(){
		this.femModel.init();
		this.numberEquations();
	}
	
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#numberEquations(br.ufmg.dees.insane.model.femModel.node.Node)
	 */
	public void numberEquations(Node node){
		this.setSizeOfXu(0);
			for (int i=0; i<node.getNumberOfDegreesOfFreedom(); i++){
				if (!node.getNodeValues(node.RESTRAINTS).getBooleanPointValue(i) ){
					this.setSizeOfXu(this.getSizeOfXu()+1);
					node.getNodeValues(node.EQUATIONS).setPointValueAsInt(i, this.getSizeOfXu());
				}
				else {
					this.setSizeOfXp(this.getSizeOfXp()+1);
					node.getNodeValues(node.EQUATIONS).setPointValueAsInt(i, -this.getSizeOfXp());
				};
			};
		};
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#numberEquations(java.util.ArrayList)
	 */
	public void numberEquations(ArrayList nodesList){
	    	this.setSizeOfXu(0);
			Node node;
			ListIterator nodes = nodesList.listIterator();
			while (nodes.hasNext()) {
				node = (Node)nodes.next();
				for (int i=0; i<node.getNumberOfDegreesOfFreedom(); i++){
					if (!node.getNodeValues(node.RESTRAINTS).getBooleanPointValue(i) ){
						this.setSizeOfXu(this.getSizeOfXu()+1);
						node.getNodeValues(node.EQUATIONS).setPointValueAsInt(i, this.getSizeOfXu());
					}
					else {
						this.setSizeOfXp(this.getSizeOfXp()+1);
						node.getNodeValues(node.EQUATIONS).setPointValueAsInt(i, -this.getSizeOfXp());
					};
				}
			};
		};	
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#update()
	 */
	public void update(){
        this.femModel.update();
     }
	
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.assembler.Assembler#clean()
	 */
	public void clean() {
		this.femModel.clean();
	}

	/** Numbers the equations of an Element.<p>
	*<b><i>Method numberNodeEquations() must have been previously called.</i></b><p>
	*Positive numbers are related to possible displacements.<br>
	*Negative numbers are related to restraints to that displacement.<br>
	*Zero is related to invalid displacement to that type of AnalysisModel.
	*@see #numberNodeEquations
	*/
	private int[] getElementEquations(Element e){
		int[] equations = new int[e.getNumberOfDegreesOfFreedom()];
	    Node node;
		ListIterator nodes = e.getIncidence().listIterator();
			int i=0;
			while (nodes.hasNext()) {
				node = (Node) nodes.next();
				for (int j=0; j<node.getNumberOfDegreesOfFreedom(); j++) {
					equations[j+i] = node.getNodeValues(node.EQUATIONS).getIntPointValue(j);
				};
			i+=node.getNumberOfDegreesOfFreedom();
			};
			return equations;
		};
		
		public void setLoading(LoadCombination lc){
			Iterator iterator = lc.getLoadCasesList().iterator();
			while (iterator.hasNext()) {
				LoadCase lcase = (LoadCase) iterator.next();
				HashMap lmap = this.getModel().getLoading(lcase.getLabel()).getNodalValues();
				Set keys = lmap.keySet();
				Iterator iter = keys.iterator();
				while (iter.hasNext()) {
					Node node = (Node) iter.next();
					DoublePointValues dpv = (DoublePointValues)lmap.get(node);
					dpv.scale(lcase.getFactor());
					node.addNodeValues(Node.DUAL_VARIABLE, dpv);
				}
			}
		}
			 
		public void addLoading(LoadCombination lc){
			Iterator iterator = lc.getLoadCasesList().iterator();
			while (iterator.hasNext()) {
				LoadCase lcase = (LoadCase) iterator.next();
				HashMap lmap = this.getModel().getLoading(lcase.getLabel()).getNodalValues();
				Set keys = lmap.keySet();
				Iterator iter = keys.iterator();
				while (iter.hasNext()) {
					Node node = (Node) iter.next();
					DoublePointValues dpv = (DoublePointValues)lmap.get(node);
					dpv.scale(lcase.getFactor());
					node.initNodeValues(Node.DUAL_VARIABLE, dpv);
				}
			}
		}
		
		public void initLoading(){
			Iterator iterator = this.getModel().getNodesList().iterator();
			while (iterator.hasNext()) {
				Node node = (Node) iterator.next();
				DoublePointValues dualVar = new DoublePointValues();
				for(int i=0; i<node.getNumberOfDegreesOfFreedom(); i++){
					dualVar.addPointValue(0.0);
			    }
				node.setNodeValues(Node.DUAL_VARIABLE, dualVar);
			}
		}
		
} // end of FemAssembler